﻿Imports System.ComponentModel
Imports System.Diagnostics

Namespace ViewModel
    Public MustInherit Class AbstractViewModel
        Implements INotifyPropertyChanged
        Implements IDisposable

#Region "Constructor"

        Protected Sub New()
        End Sub

#End Region

#Region "Properties"

        Protected _displayName As String
        Public Overridable Property DisplayName() As String
            Get
                Return _displayName
            End Get
            Set(ByVal value As String)
                _displayName = value
            End Set
        End Property

#End Region

#Region "Debugging Aides"

        <Conditional("DEBUG")> _
        <DebuggerStepThrough()> _
        Public Sub VerifyPropertyName(ByVal propertyName As String)
            If TypeDescriptor.GetProperties(Me)(propertyName) Is Nothing Then
                Dim message As String = "Invalid property name: " & propertyName

                If Me.ThrowOnInvalidPropertyName Then
                    Throw New Exception(message)
                Else
                    Debug.Fail(message)
                End If
            End If
        End Sub

        ''' <summary>
        ''' Returns whether an exception is thrown, or if a Debug.Fail() is used
        ''' when an invalid property name is passed to the VerifyPropertyName method.
        ''' The default value is false, but subclasses used by unit tests might 
        ''' override this property's getter to return true.
        ''' </summary>
        Protected Overridable Property ThrowOnInvalidPropertyName() As Boolean
            Get
                Return _throwOnInvalidPropertyName
            End Get
            Set(ByVal value As Boolean)
                _throwOnInvalidPropertyName = value
            End Set
        End Property
        Protected _throwOnInvalidPropertyName As Boolean

#End Region

#Region "INotifyPropertyChanged Members"

        ''' <summary>
        ''' Raised when a property on this object has a new value.
        ''' </summary>
        Public Event PropertyChanged As PropertyChangedEventHandler _
            Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged

        ''' <summary>
        ''' Raises this object's PropertyChanged event.
        ''' </summary>
        ''' <param name="propertyName">The property that has a new value.</param>
        Protected Overridable Sub OnPropertyChanged(ByVal propertyName As String)
            Me.VerifyPropertyName(propertyName)

            Dim handler As PropertyChangedEventHandler = Me.PropertyChangedEvent

            If handler IsNot Nothing Then
                handler.Invoke(Me, New PropertyChangedEventArgs(propertyName))
            End If
        End Sub

#End Region

#Region "IDisposable Members"

        ''' <summary>
        ''' Invoked when this object is being removed from the application
        ''' and will be subject to garbage collection.
        ''' </summary>
        Public Sub Dispose() _
            Implements IDisposable.Dispose

            Me.OnDispose()
        End Sub

        ''' <summary>
        ''' Child classes can override this method to perform 
        ''' clean-up logic, such as removing event handlers.
        ''' </summary>
        Protected Overridable Sub OnDispose()
        End Sub

#If DEBUG Then
        ''' <summary>
        ''' Useful for ensuring that ViewModel objects are properly garbage collected.
        ''' </summary>
        Protected Overrides Sub Finalize()
            Dim msg As String = String.Format("{0} ({1}) ({2}) Finalized", Me.[GetType]().Name, Me.DisplayName, Me.GetHashCode())
            System.Diagnostics.Debug.WriteLine(msg)
        End Sub
#End If

#End Region

    End Class
End Namespace
